﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Soleil.Domain.Core.DomainObjects;
using Soleil.Domain.Core.Repositories;

namespace Infrastructure.Data.EF.Core.Repositories
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : DomainObject
    {
        private IObjectSet<TEntity> objectSet;

        public EFUnitOfWork UnitOfWork { get; private set; }

        public Repository(EFUnitOfWork unitOfWork)
        {
            UnitOfWork = unitOfWork;

            // Create objectset to work with.
            if (UnitOfWork != null && UnitOfWork.DbContext != null)
            {
                objectSet = UnitOfWork.DbContext.CreateObjectSet<TEntity>();
            }
        }


        public void Dispose()
        {
            if(UnitOfWork != null)
                UnitOfWork.Dispose();
        }

        public TEntity FindBy(int id)
        {
            return objectSet.SingleOrDefault(x => x.Id == id);
        }

        public bool TryFindBy(ref TEntity result, int id)
        {
            result = FindBy(id);

            return result != null;
        }

        public bool Add(TEntity entity)
        {
            objectSet.AddObject(entity);
            return true;
        }

        public bool Add(IEnumerable<TEntity> entities)
        {
            foreach (var entity in entities)
            {
                Add(entity);
            }

            return true;
        }

        public bool Update(TEntity entity)
        {
            throw new NotImplementedException();
        }

        public bool Delete(TEntity entity)
        {
            objectSet.DeleteObject(entity);
            return true;
        }

        public bool Delete(IEnumerable<TEntity> entities)
        {
            foreach (var entity in entities)
            {
                Delete(entity);
            }
            return true;
        }

        public IQueryable<TEntity> All()
        {
            return objectSet;
        }

        public IList<TEntity> GetAll()
        {
            return objectSet.ToList();
        }

        public TEntity FindBy(Expression<Func<TEntity, bool>> expression)
        {
            return All().Where(expression).SingleOrDefault();
        }

        public bool TryFindBy(ref TEntity result, Expression<Func<TEntity, bool>> expression)
        {
            result = FindBy(expression);

            return result != null;
        }

        public IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression)
        {
            return All().Where(expression);
        }

        public void LoadProperty(object ownerObject, object property)
        {
            throw new NotImplementedException();
        }
    }
}
